use async_std::net::TcpStream;
use futures::{SinkExt, StreamExt};

use crate::prelude::*;
use crate::Result;

#[async_trait::async_trait]
pub trait FramedWriteExt {
    async fn send_ext<T>(&mut self, msg: T) -> Result<()>
    where
        T: HoneybeeMessage;
}

#[async_trait::async_trait]
impl FramedWriteExt for FramedWrite<Compat<TcpStream>, HoneybeeMsgCodec> {
    async fn send_ext<T>(&mut self, msg: T) -> Result<()>
    where
        T: HoneybeeMessage,
    {
        self.send(HoneybeeMsg {
            session: 0,
            msg: &msg,
        })
        .await
        .map_err(|err| err.into())
    }
}

#[async_trait::async_trait]
pub trait FramedReadExt {
    async fn read_msg<T>(&mut self) -> Result<T>
    where
        T: HoneybeeMessage;
}

#[async_trait::async_trait]
impl FramedReadExt for FramedRead<Compat<TcpStream>, HoneybeeMsgCodec> {
    async fn read_msg<T>(&mut self) -> Result<T>
    where
        T: HoneybeeMessage,
    {
        let raw_msg = self.next().await.ok_or_else(|| anyhow!("None"))??;
        bincode::deserialize(raw_msg.bytes.as_ref()).map_err(|err| err.into())
    }
}
